package org.dromara.web.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.domain.model.XcxLoginBody;
import org.dromara.common.core.domain.model.XcxLoginUser;
import org.dromara.common.core.enums.UserStatus;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.ValidatorUtils;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.domain.FXcxUser;
import org.dromara.system.domain.SysClient;
import org.dromara.system.domain.SysUser;
import org.dromara.system.domain.bo.FXcxUserBo;
import org.dromara.system.domain.vo.FXcxUserVo;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.mapper.SysUserMapper;
import org.dromara.system.service.IFXcxUserService;
import org.dromara.web.domain.vo.LoginVo;
import org.dromara.web.service.IAuthStrategy;
import org.dromara.web.service.SysLoginService;
import org.springframework.stereotype.Service;

import java.util.HashSet;

/**
 * 邮件认证策略
 *
 * @author Michelle.Chung
 */
@Slf4j
@Service("xcx" + IAuthStrategy.BASE_NAME)
@RequiredArgsConstructor
public class XcxAuthStrategy implements IAuthStrategy {

    private final SysLoginService loginService;

    private final WxMaService wxMaService;

    private final IFXcxUserService fXcxUserService;

    private final SysUserMapper sysUserMapper;




    @Override
    public LoginVo login(String body, SysClient client) {
        XcxLoginBody loginBody = JsonUtils.parseObject(body, XcxLoginBody.class);
        ValidatorUtils.validate(loginBody);
        // xcxCode 为 小程序调用 wx.login 授权后获取
        String xcxCode = loginBody.getAppCode();
        // 多个小程序识别使用
        String appid = loginBody.getAppid();

        // todo 以下自行实现
        // 校验 appid + appsrcret + xcxCode 调用登录凭证校验接口 获取 session_key 与 openid
          if (!wxMaService.switchover(appid)){
             throw new ServiceException("小程序配置不存在");
         }
        String openid = null;
        String sessionKey = null;
        String unionId = null;
        try {
            WxMaJscode2SessionResult sessionInfo = wxMaService.getUserService().getSessionInfo(xcxCode);
            openid = sessionInfo.getOpenid();
            sessionKey = sessionInfo.getSessionKey();
            unionId = sessionInfo.getUnionid();
            Console.log("openid:{}",openid);
            Console.log("sessionKey:{}",sessionKey);
            Console.log("unionId:{}",unionId);
        } catch (WxErrorException e) {
            throw new RuntimeException(e);
        }

        // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
        FXcxUserVo user = loadUserByOpenid(openid);
        //SysUser user = loadUserByOpenid(openid);

        // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
        XcxLoginUser loginUser = new XcxLoginUser();
        loginUser.setUserId(user.getId());
        loginUser.setUsername(user.getNickename());
        loginUser.setUserType("app_user");
        loginUser.setClientKey(client.getClientKey());
        loginUser.setDeviceType(client.getDeviceType());
        loginUser.setOpenid(openid);
        loginUser.setSessionKey(sessionKey);

        // 设置权限
        HashSet<String> menuPermission = new HashSet<>();
        menuPermission.add("app:xcxUser:list");
        menuPermission.add("app:xcxUser:add");
        loginUser.setMenuPermission(menuPermission);
        HashSet roles = new HashSet<>();
        roles.add("app_user");
        loginUser.setRolePermission(roles);

        SaLoginModel model = new SaLoginModel();
        model.setDevice(client.getDeviceType());
        // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置
        // 例如: 后台用户30分钟过期 app用户1天过期
        model.setTimeout(client.getTimeout());
        model.setActiveTimeout(client.getActiveTimeout());
        model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId());
        // 生成token
        LoginHelper.login(loginUser, model);

        LoginVo loginVo = new LoginVo();
        loginVo.setAccessToken(StpUtil.getTokenValue());
        loginVo.setExpireIn(StpUtil.getTokenTimeout());
        loginVo.setClientId(client.getClientId());
        loginVo.setOpenid(openid);
        loginVo.setRolePermission(menuPermission);
        return loginVo;
    }

    private FXcxUserVo loadUserByOpenid(String openid) {
        // 使用 openid 查询绑定用户 如未绑定用户 则根据业务自行处理 例如 创建默认用户
        FXcxUserVo xcxUserVo = fXcxUserService.selectUserByOpenid(openid);

        // 新增用户
        if (ObjectUtil.isNull(xcxUserVo)) {

            // todo 用户不存在 业务逻辑自行实现
            xcxUserVo = fXcxUserService.newXcxUser(openid);

        }
        xcxUserVo = fXcxUserService.selectUserByOpenid(xcxUserVo.getOpenid());
            if (ObjectUtil.isNull(xcxUserVo)){
                xcxUserVo.setId(xcxUserVo.getId());
                xcxUserVo.setNickename(xcxUserVo.getNickename());
                fXcxUserService.insertByBo(BeanUtil.toBean(xcxUserVo, FXcxUserBo.class));
            }else {
                fXcxUserService.updateByBo(BeanUtil.toBean(xcxUserVo,FXcxUserBo.class));
            }
            /*else if (UserStatus.DISABLE.getCode().equals(sysUser.getStatus())) {
                throw new ServiceException("用户被禁用");
            }*/


        return xcxUserVo;
    }

}
